# 导入所需的库和模块
import matplotlib.pyplot as plt  # 用于绘制数据可视化图形，例如折线图、散点图等
import pandas as pd  # 用于数据处理和分析，提供了高效的数据结构和数据操作功能
import statsmodels.api as sm  # 用于执行统计模型的拟合和推断，包括回归分析、时间序列分析等
from sklearn.linear_model import LinearRegression  # 用于进行线性回归建模和预测
from sklearn.model_selection import train_test_split  # 将数据集分割为训练集和测试集，常用于机器学习中的模型评估和验证

from DrawingImages import DrawGraphics


def multiple_linear_regression(file_path):
    # 1.读取数据并处理
    data = pd.read_excel(file_path)  # 使用pd.read_excel()函数读取名为'客户价值数据表.xlsx'的Excel文件，并将其存储在data变量中
    # 根据指定的测试集比例（这里是20%）将数据分割为训练集和测试集，并且设置了一个随机种子（这里是42）以确保结果可复现
    train_data, test_data = train_test_split(data, test_size=0.2, random_state=42)
    X = data[['历史贷款金额', '贷款次数', '学历', '月收入', '性别']]  # 从data中选取'历史贷款金额'、'贷款次数'、'学历'、'月收入'、'性别'这几列作为自变量，并将其存储在X变量中
    Y = data['客户价值']  # 从data中选取'客户价值'这一列作为因变量，并将其存储在Y变量中
    X_test = test_data[['历史贷款金额', '贷款次数', '学历', '月收入', '性别']]
    Y_test = test_data[['客户价值']]

    # 2.搭建多元线性回归模型
    Regress = LinearRegression()  # 创建一个LinearRegression对象，并将其存储在Regress变量中
    Regress.fit(X, Y)  # 使用X和Y进行线性回归拟合，得到回归模型
    Predict = Regress.predict(X)  # 对五个特征变量进行回归预测

    # 2.1绘制真实值和与测试值的散点图形
    plt.scatter(Y, Predict)
    plt.plot([Y.min(), Y.max()], [Y.min(), Y.max()], 'r-')  # 绘制一条辅助线

    # 2.2设置图例
    plt.xlabel('Actual Value')
    plt.ylabel('Predicted Value')
    plt.title('Regression Graph')
    plt.show()  # 显示

    # 3.构造多元线性回归方程表达式
    K = Regress.coef_
    b = Regress.intercept_
    print('各斜率系数为:\n', str(K))  # 打印输出回归模型的各系数值
    print('常数项系数k0（截距）为:\n', str(b))  # 打印输出回归模型的常数项系数k0
    expression = construct_expression(K, b)  # 计算多元线性回归方程函数表达式
    print("多元线性回归方程为：\nY = ", expression)
    DrawGraphics(expression)  # 绘制多元线性回归方程表达式图像

    # 4.模型预测
    predict_new_data(Regress, X_test, Y_test)

    # 5.模型评估
    X1 = sm.add_constant(X)  # 在X变量中添加常数列，即截距b，并将新的X变量存储在X1中
    est = sm.OLS(Y, X1).fit()  # 使用OLS方法进行普通最小二乘回归拟合，得到回归模型的估计值，将结果存储在est变量中
    print('\n\n回归模型的统计摘要信息如下:\n', est.summary())  # 输出回归模型的统计摘要信息


# 构造函数表达式
# 表达式中的系数值在-1到1之间的要保留三位小数，系数值在-10到-1以及1到10之间的要保留两位小数，其余保留整数
def construct_expression(K, b):
    expression = f"{int(b)}"
    for i, coef in enumerate(K):
        if -10 <= coef <= -1 or 1 <= coef <= 10:
            expression += f" + {coef:.2f}*X{i + 1}"
        elif -1 <= coef <= 1:
            expression += f" + {coef:.3f}*X{i + 1}"
        else:
            expression += f" + {int(coef)}*X{i + 1}"
    return expression


# 模型预测
def predict_new_data(model, X_new, Y_new):
    print("\n\n\n\n模型预测使用的数据如下：\n", X_new)
    new_prediction = model.predict(X_new)
    print('模型预测数据的预测结果:\n', new_prediction)
    # 绘制真实值与预测值对比图
    plt.plot(Y_new['客户价值'].tolist(), label='Actual Value')
    plt.plot(new_prediction, label='Predicted Value')
    plt.xlabel('Sample Index')
    plt.ylabel('Value')
    plt.title('Regression Curve Comparison')
    plt.legend()  # 添加图例
    plt.show()


# 程序入口
if __name__ == '__main__':
    path = '客户价值数据表.xlsx'
    multiple_linear_regression(path)  # 调用函数并传入数据文件的路径
